'''
huoni PLC通讯
点位名称和功能
序号	英文名	中文名	功能
1	LoadEmptyCarton	空盒上料	引导	无
2	UnloadFullCarton	满盒下料	无	无
3	PlaceCarton	纸盒放置	无	检测
4	PlaceBat	电池放置	引导	检测
5	PlacePhone	手机放置	引导	检测
6	PlaceCable	数据线放置	引导	检测
7	PlaceStrap	腕带放置	引导	检测
8	PlaceScrew	螺丝放置	引导	检测
9	PlaceManual	说明书放置	引导	检测
	PlaceLicence	许可证放置	引导	检测

'''
import sys
import threading
import time
import traceback

import snap7

# sys.path.append(r'D:\code\huoNiWeiEr\project_huoni_v2\neith_fyluoding\plc_S7')
# from plc_S7.s7_client import S7Client
try:
    from .s7_client import S7Client
    from .s7_client_sim import SimClient
except:
    from plc_S7.s7_client import S7Client
    from plc_S7.s7_client_sim import SimClient

from midea_common.defconfig_common import logger


class Config:
    # ip = '127.0.0.1' # 本地测试用 启动模拟服务端命令 snap7-server
    # port = 1102
    # rack = 0
    # slot = 0
    # dbnumber = 0

    ip = '192.168.0.1'
    port = 102
    rack = 0
    slot = 0
    dbnumber = 183

    MainTh = {'is_ready': 306, 'get_product_type_id': {'dbnumber': 212, 'address': 4}}  #
    # 点位1 空盒上料
    LoadEmptyCarton = {'is_yd': 4, 'is_jc': 2, 'set_yd_res': [5, 8, 12, 16], 'set_jc_res': 3}  # 空盒上料

    # 点位8 满盒下料
    UnloadFullCarton = {'is_yd': 38, 'is_jc': 36, 'set_yd_res': [39, 42, 46, 50], 'set_jc_res': 37}  # 满盒下料

    # # 点位8 纸盒放置
    # PlaceCarton = {'is_yd': 4, 'is_jc': 2, 'set_yd_res': [5, 8, 12, 16], 'set_jc_res': 3}  # 纸盒放置

    # 点位2 电池放置
    PlaceBat = {'is_yd': 72, 'is_jc': 70, 'set_yd_res': [73, 76, 80, 84], 'set_jc_res': 71,
                'is_jc2': 344, 'set_jc_res2': 345, }

    # 点位3 数据线放置
    PlaceCable = {'is_yd': 140, 'is_jc': 138, 'set_yd_res': [141, 144, 148, 152], 'set_jc_res': 139,
                  'get_xyu': [156, 160, 164]}  # 数据线放置 点位3

    # 点位4 螺丝放置
    PlaceScrew = {'is_yd': 242, 'is_jc': 240, 'set_yd_res': [243, 246, 250, 254], 'set_jc_res': 241,
                  'get_xyu': [258, 262, 266]}

    # 点位5 说明书放置 许可证放置
    PlaceInstruction = {'is_yd': 208, 'is_jc': 206, 'set_yd_res': [209, 212, 216, 220], 'set_jc_res': 207,
                        'set_scan_res': {'dbnumber': 219, 'address': 228}}  # 扫码结果放在另一个db块 228

    # 点位5_2 # is_scan 视觉扫码触发， set_scan_res 视觉扫码结果（int），
    PlaceLicence = {'is_yd': 276, 'is_jc': 274, 'set_yd_res': [277, 280, 284, 288], 'set_jc_res': 275,
                    'set_scan_res': {'dbnumber': 219, 'address': 284}}  # 许可证放置 扫码结果放在另一个db块

    # 点位6 腕带 DA1851911
    PlaceStrap = {'is_yd': 174, 'is_jc': 172, 'set_yd_res': [175, 178, 182, 186], 'set_jc_res': 173,
                  'get_xyu': [190, 194, 198]}  #

    # 地址表
    # 点位7 手机放置
    # [是否引导 uint8 复位0/不引导1/引导2 ， 是否检测 0/1 ，引导结果 [是否ok uint8, x坐标 real, y坐标 real, 角度 real,]  ， 检测结果 0/1/2]
    PlacePhone = {'is_yd': 106, 'is_jc': 104, 'set_yd_res': [107, 110, 114, 118], 'set_jc_res': 105,
                  'set_scan_res': {'dbnumber': 219, 'address': 60}}  # 手机放置

    # 点位9 标贴检测
    DetectLabel = {'is_yd': 312, 'is_jc': 310, 'set_yd_res': [313, 316, 320, 324], 'set_jc_res': 311,
                   }


config = Config()  #


class HuoniPlcClientBase:  # 一个点位一个plc客户端 （各点位plc逻辑类似）
    def __init__(self, addressTable=Config().LoadEmptyCarton, driver='s7_tcp'):
        if driver == 'sim':
            self.s7client = SimClient(config.ip, config.port, config.dbnumber)
        else:
            self.s7client = S7Client(config.ip, config.port, config.dbnumber)
        self.addressTable = addressTable
        self.lock = threading.Lock()  # 同步

    def connect(self):
        self.s7client.connect()
        print(self.addressTable)

    def close(self):
        self.s7client.close()

    def isConnected(self):
        return self.s7client.get_connected()

    def get_is_yd(self):  # 是否引导
        try:
            self.lock.acquire()
            is_yd = self.s7client.read_int8(start=self.addressTable['is_yd'])
            self.lock.release()
        except Exception as e:
            self.lock.release()
            logger.error(self.addressTable)
            logger.error(traceback.format_exc())
            # self.lock.acquire()
            self.lock.acquire()
            logger.info('重连中...')
            self.close()
            self.connect()  # 重连
            time.sleep(1)
            self.lock.release()
            return 0

        return is_yd

    def get_is_jc(self):  # 是否检测
        try:
            self.lock.acquire()
            is_jc = self.s7client.read_int8(start=self.addressTable['is_jc'])
            self.lock.release()
        except Exception as e:
            self.lock.release()  # 释放
            logger.error(self.addressTable)
            logger.error(traceback.format_exc())
            self.lock.acquire()
            logger.info('重连中...')
            self.close()
            self.connect()  # 重连
            self.lock.release()
            return 0
        return is_jc

    def get_is_jc2(self):  # 是否检测
        try:
            self.lock.acquire()
            is_jc = self.s7client.read_int8(start=self.addressTable['is_jc2'])
            self.lock.release()
        except Exception as e:
            self.lock.release()  # 释放
            logger.error(self.addressTable)
            logger.error(traceback.format_exc())
            self.lock.acquire()
            logger.info('重连中...')
            self.close()
            self.connect()  # 重连
            self.lock.release()
            return 0
        return is_jc

    def set_zero_is_yd(self):  # 是否引导 置0
        self.lock.acquire()
        self.s7client.write_int8(start=self.addressTable['is_yd'], data_int8=0)
        self.lock.release()
        return

    def set_zero_is_jc(self):  # 是否检测 置0
        self.lock.acquire()
        self.s7client.write_int8(start=self.addressTable['is_jc'], data_int8=0)
        self.lock.release()
        return

    def set_zero_is_jc2(self):  # 是否检测 置0
        self.lock.acquire()
        self.s7client.write_int8(start=self.addressTable['is_jc2'], data_int8=0)
        self.lock.release()
        return

    def set_yd_res(self, yd_res):  # 引导结果
        self.lock.acquire()
        try:
            # 引导结果 [ 结果状态 uint8  1 ok 2 无料 3 放反,    x坐标 real, y坐标 real, 角度 real,]
            status, x_real, y_real, degree_real = yd_res
            # t1 = time.time()
            self.s7client.write_real(start=self.addressTable['set_yd_res'][1], data_real=x_real)
            self.s7client.write_real(start=self.addressTable['set_yd_res'][2], data_real=y_real)
            self.s7client.write_real(start=self.addressTable['set_yd_res'][3], data_real=degree_real)
            self.s7client.write_int8(start=self.addressTable['set_yd_res'][0], data_int8=status)
            # print(f'yd_res {time.time()-t1} s')
        except Exception as e:
            logger.error('发送引导结果失败')
            # print(e)
        self.lock.release()

    def set_jc_res(self, jc_res):  # 检测结果
        # 检测结果 0/1/2
        self.lock.acquire()
        self.s7client.write_int8(start=self.addressTable['set_jc_res'], data_int8=jc_res)
        self.lock.release()

    def set_jc_res2(self, jc_res):  # 检测结果
        # 检测结果 0/1/2
        self.lock.acquire()
        self.s7client.write_int8(start=self.addressTable['set_jc_res2'], data_int8=jc_res)
        self.lock.release()

    def get_xyu(self):  # 读取机械臂坐标，用于9点标定
        self.lock.acquire()
        x = self.s7client.read_real(start=self.addressTable['get_xyu'][0])
        y = self.s7client.read_real(start=self.addressTable['get_xyu'][1])
        u = self.s7client.read_real(start=self.addressTable['get_xyu'][2])
        self.lock.release()
        return x, y, u

    def set_is_ready(self, is_ready):
        self.lock.acquire()
        self.s7client.write_bool(start=self.addressTable['is_ready'], data_bool=is_ready)
        self.lock.release()

    def set_scan_res(self, scan_str):
        self.lock.acquire()
        self.s7client.write_string(start=self.addressTable['set_scan_res']['address'],
                                   data_str=scan_str, dbnumber=self.addressTable['set_scan_res']['dbnumber'])
        self.lock.release()
    def get_scan_res(self):
        self.lock.acquire()
        value = self.s7client.read_string(start=self.addressTable['set_scan_res']['address'],
                                  dbnumber=self.addressTable['set_scan_res']['dbnumber'])
        self.lock.release()
        return value

    def get_product_type_id(self):
        self.lock.acquire()
        product_type_id = self.s7client.read_int8(start=self.addressTable['get_product_type_id']['address'],
                                                  dbnumber=self.addressTable['get_product_type_id']['dbnumber'])
        self.lock.release()
        return product_type_id


class HuoniPlcClient:  # 业务相关

    def __init__(self):
        self.s7client = S7Client(config.ip, config.port, config.dbnumber)

    def connect(self):
        self.s7client.connect()

    def close(self):
        self.s7client.close()

    '''
    点位1 
    空盒上料
    '''

    def get_is_yd_loadEmptyCarton(self):  # 是否引导
        is_yd = self.s7client.read_int8(start=config.LoadEmptyCarton['is_yd'])
        return is_yd

    def get_is_jc_loadEmptyCarton(self):  # 是否检测
        is_jc = self.s7client.read_int8(start=config.LoadEmptyCarton['is_jc'])
        return is_jc

    def set_zero_is_yd_loadEmptyCarton(self):  # 是否引导 置0
        self.s7client.write_int8(start=config.LoadEmptyCarton['is_yd'], data_int8=0)
        return

    def set_zero_is_jc_loadEmptyCarton(self):  # 是否检测 置0
        self.s7client.write_int8(start=config.LoadEmptyCarton['is_jc'], data_int8=0)
        return

    def set_yd_res_loadEmptyCarton(self, yd_res):  # 引导结果
        # 引导结果 [ 结果状态 uint8  1 ok 2 无料 3 放反,    x坐标 real, y坐标 real, 角度 real,]
        status, x_real, y_real, degree_real = yd_res
        # t1 = time.time()
        self.s7client.write_int8(start=config.LoadEmptyCarton['set_yd_res'][0], data_int8=status)
        self.s7client.write_real(start=config.LoadEmptyCarton['set_yd_res'][1], data_real=x_real)
        self.s7client.write_real(start=config.LoadEmptyCarton['set_yd_res'][2], data_real=y_real)
        self.s7client.write_real(start=config.LoadEmptyCarton['set_yd_res'][3], data_real=degree_real)
        # print(f'yd_res {time.time()-t1} s')

    def set_jc_res_loadEmptyCarton(self, jc_res):  # 检测结果
        # 检测结果 0/1/2
        self.s7client.write_int8(start=config.LoadEmptyCarton['set_jc_res'], data_int8=jc_res)

    '''
    点位2 
    电池放置
    '''

    def get_is_yd_placeBat(self):  # 是否引导
        is_yd = self.s7client.read_int8(start=config.PlaceBat['is_yd'])
        return is_yd

    def get_is_jc_placeBat(self):  # 是否检测
        is_jc = self.s7client.read_int8(start=config.PlaceBat['is_jc'])
        return is_jc

    def set_zero_is_yd_placeBat(self):  # 是否引导 置0
        self.s7client.write_int8(start=config.PlaceBat['is_yd'], data_int8=0)
        return

    def set_zero_is_jc_placeBat(self):  # 是否检测 置0
        self.s7client.write_int8(start=config.PlaceBat['is_jc'], data_int8=0)
        return

    def set_yd_res_placeBat(self, yd_res):  # 引导结果
        # 引导结果 [ 结果状态 uint8  1 ok 2 无料 3 放反,    x坐标 real, y坐标 real, 角度 real,]
        status, x_real, y_real, degree_real = yd_res
        # t1 = time.time()
        self.s7client.write_int8(start=config.PlaceBat['set_yd_res'][0], data_int8=status)
        self.s7client.write_real(start=config.PlaceBat['set_yd_res'][1], data_real=x_real)
        self.s7client.write_real(start=config.PlaceBat['set_yd_res'][2], data_real=y_real)
        self.s7client.write_real(start=config.PlaceBat['set_yd_res'][3], data_real=degree_real)
        # print(f'yd_res {time.time()-t1} s')

    def set_jc_res_placeBat(self, jc_res):  # 检测结果
        # 检测结果 0/1/2
        self.s7client.write_int8(start=config.PlaceBat['set_jc_res'], data_int8=jc_res)

    '''
    # 点位3 
    数据线放置
    '''

    def get_is_yd_placeCable(self):  # 是否引导
        is_yd = self.s7client.read_int8(start=config.PlaceCable['is_yd'])
        return is_yd

    def get_is_jc_placeCable(self):  # 是否检测
        is_jc = self.s7client.read_int8(start=config.PlaceCable['is_jc'])
        return is_jc

    def set_zero_is_yd_placeCable(self):  # 是否引导 置0
        self.s7client.write_int8(start=config.PlaceCable['is_yd'], data_int8=0)
        return

    def set_zero_is_jc_placeCable(self):  # 是否检测 置0
        self.s7client.write_int8(start=config.PlaceCable['is_jc'], data_int8=0)
        return

    def set_yd_res_placeCable(self, yd_res):  # 引导结果
        # 引导结果 [ 结果状态 uint8  1 ok 2 无料 3 放反,    x坐标 real, y坐标 real, 角度 real,]
        status, x_real, y_real, degree_real = yd_res
        # t1 = time.time()
        self.s7client.write_int8(start=config.PlaceCable['set_yd_res'][0], data_int8=status)
        self.s7client.write_real(start=config.PlaceCable['set_yd_res'][1], data_real=x_real)
        self.s7client.write_real(start=config.PlaceCable['set_yd_res'][2], data_real=y_real)
        self.s7client.write_real(start=config.PlaceCable['set_yd_res'][3], data_real=degree_real)
        # print(f'yd_res {time.time()-t1} s')

    def set_jc_res_placeCable(self, jc_res):  # 检测结果
        # 检测结果 0/1/2
        self.s7client.write_int8(start=config.PlaceCable['set_jc_res'], data_int8=jc_res)

    '''
    点位4 
    螺丝  充电器放置
    Screw
    '''

    def get_is_yd_placeScrew(self):  # 是否引导
        is_yd = self.s7client.read_int8(start=config.PlaceScrew['is_yd'])
        return is_yd

    def get_is_jc_placeScrew(self):  # 是否检测
        is_jc = self.s7client.read_int8(start=config.PlaceScrew['is_jc'])
        return is_jc

    def set_zero_is_yd_placeScrew(self):  # 是否引导 置0
        self.s7client.write_int8(start=config.PlaceScrew['is_yd'], data_int8=0)
        return

    def set_zero_is_jc_placeScrew(self):  # 是否检测 置0
        self.s7client.write_int8(start=config.PlaceScrew['is_jc'], data_int8=0)
        return

    def set_yd_res_placeScrew(self, yd_res):  # 引导结果
        # 引导结果 [ 结果状态 uint8  1 ok 2 无料 3 放反,    x坐标 real, y坐标 real, 角度 real,]
        status, x_real, y_real, degree_real = yd_res
        # t1 = time.time()
        self.s7client.write_int8(start=config.PlaceScrew['set_yd_res'][0], data_int8=status)
        self.s7client.write_real(start=config.PlaceScrew['set_yd_res'][1], data_real=x_real)
        self.s7client.write_real(start=config.PlaceScrew['set_yd_res'][2], data_real=y_real)
        self.s7client.write_real(start=config.PlaceScrew['set_yd_res'][3], data_real=degree_real)
        # print(f'yd_res {time.time()-t1} s')

    def set_jc_res_placeScrew(self, jc_res):  # 检测结果
        # 检测结果 0/1/2
        self.s7client.write_int8(start=config.PlaceScrew['set_jc_res'], data_int8=jc_res)

    def get_xyu_placeScrew(self):  # 读取机械臂坐标，用于9点标定

        x = self.s7client.read_real(start=config.PlaceScrew['get_xyu'][0])
        y = self.s7client.read_real(start=config.PlaceScrew['get_xyu'][1])
        u = self.s7client.read_real(start=config.PlaceScrew['get_xyu'][2])
        return x, y, u

    '''
    点位5 
    说明书 许可证 放置
    Screw
    '''

    def get_is_yd_placeInstruction(self):  # 是否引导
        is_yd = self.s7client.read_int8(start=config.PlaceInstruction['is_yd'])
        return is_yd

    def get_is_jc_placeInstruction(self):  # 是否检测
        is_jc = self.s7client.read_int8(start=config.PlaceInstruction['is_jc'])
        return is_jc

    def set_zero_is_yd_placeInstruction(self):  # 是否引导 置0
        self.s7client.write_int8(start=config.PlaceInstruction['is_yd'], data_int8=0)
        return

    def set_zero_is_jc_placeInstruction(self):  # 是否检测 置0
        self.s7client.write_int8(start=config.PlaceInstruction['is_jc'], data_int8=0)
        return

    def set_yd_res_placeInstruction(self, yd_res):  # 引导结果
        # 引导结果 [ 结果状态 uint8  1 ok 2 无料 3 放反,    x坐标 real, y坐标 real, 角度 real,]
        status, x_real, y_real, degree_real = yd_res
        # t1 = time.time()
        self.s7client.write_int8(start=config.PlaceInstruction['set_yd_res'][0], data_int8=status)
        self.s7client.write_real(start=config.PlaceInstruction['set_yd_res'][1], data_real=x_real)
        self.s7client.write_real(start=config.PlaceInstruction['set_yd_res'][2], data_real=y_real)
        self.s7client.write_real(start=config.PlaceInstruction['set_yd_res'][3], data_real=degree_real)
        # print(f'yd_res {time.time()-t1} s')

    def set_jc_res_placeInstruction(self, jc_res):  # 检测结果
        # 检测结果 0/1/2
        self.s7client.write_int8(start=config.PlaceInstruction['set_jc_res'], data_int8=jc_res)

    '''
    点位6 DA1851911
    腕带 放置 Strap
    '''

    def get_is_yd_placeStrap(self):  # 是否引导
        is_yd = self.s7client.read_int8(start=config.PlaceStrap['is_yd'])
        return is_yd

    def get_is_jc_placeStrap(self):  # 是否检测
        is_jc = self.s7client.read_int8(start=config.PlaceStrap['is_jc'])
        return is_jc

    def set_zero_is_yd_placeStrap(self):  # 是否引导 置0
        self.s7client.write_int8(start=config.PlaceStrap['is_yd'], data_int8=0)
        return

    def set_zero_is_jc_placeStrap(self):  # 是否检测 置0
        self.s7client.write_int8(start=config.PlaceStrap['is_jc'], data_int8=0)
        return

    def set_yd_res_placeStrap(self, yd_res):  # 引导结果
        # 引导结果 [ 结果状态 uint8  1 ok 2 无料 3 放反,    x坐标 real, y坐标 real, 角度 real,]
        status, x_real, y_real, degree_real = yd_res
        # t1 = time.time()
        self.s7client.write_int8(start=config.PlaceStrap['set_yd_res'][0], data_int8=status)
        self.s7client.write_real(start=config.PlaceStrap['set_yd_res'][1], data_real=x_real)
        self.s7client.write_real(start=config.PlaceStrap['set_yd_res'][2], data_real=y_real)
        self.s7client.write_real(start=config.PlaceStrap['set_yd_res'][3], data_real=degree_real)
        # print(f'yd_res {time.time()-t1} s')

    def set_jc_res_placeStrap(self, jc_res):  # 检测结果
        # 检测结果 0/1/2
        self.s7client.write_int8(start=config.PlaceStrap['set_jc_res'], data_int8=jc_res)

    def get_xyu_placeStrap(self):  # 读取机械臂坐标，用于9点标定
        x = self.s7client.read_real(start=config.PlaceStrap['get_xyu'][0])
        y = self.s7client.read_real(start=config.PlaceStrap['get_xyu'][1])
        u = self.s7client.read_real(start=config.PlaceStrap['get_xyu'][2])
        return x, y, u

    '''
    点位7  手机放置
    '''

    def get_is_yd_placePhone(self):  # 是否引导
        is_yd = self.s7client.read_int8(start=config.PlacePhone['is_yd'])
        return is_yd

    def get_is_jc_placePhone(self):  # 是否检测
        is_jc = self.s7client.read_int8(start=config.PlacePhone['is_jc'])
        return is_jc

    def set_zero_is_yd_placePhone(self):  # 是否引导 置0
        self.s7client.write_int8(start=config.PlacePhone['is_yd'], data_int8=0)
        return

    def set_zero_is_jc_placePhone(self):  # 是否检测 置0
        self.s7client.write_int8(start=config.PlacePhone['is_jc'], data_int8=0)
        return

    def set_yd_res_placePhone(self, yd_res):  # 引导结果
        # 引导结果 [ 结果状态 uint8  1 ok 2 无料 3 放反,    x坐标 real, y坐标 real, 角度 real,]
        status, x_real, y_real, degree_real = yd_res
        self.s7client.write_int8(start=config.PlacePhone['set_yd_res'][0], data_int8=status)
        self.s7client.write_real(start=config.PlacePhone['set_yd_res'][1], data_real=x_real)
        self.s7client.write_real(start=config.PlacePhone['set_yd_res'][2], data_real=y_real)
        self.s7client.write_real(start=config.PlacePhone['set_yd_res'][3], data_real=degree_real)

    def set_jc_res_placePhone(self, jc_res):  # 检测结果
        # 检测结果 0/1/2

        self.s7client.write_int8(start=config.PlacePhone['set_jc_res'], data_int8=jc_res)


def test_HuoniPlcClinet():
    hn_plc = HuoniPlcClient()
    hn_plc.connect()
    while 1:
        # 1 等待获取引导触发
        print('1 等待获取引导触发')
        while 1:
            is_yd = hn_plc.get_is_yd_placePhone()  #
            if is_yd == 1:
                print(f'is_yd {is_yd}')
                hn_plc.set_zero_is_yd_placePhone()
                break

        # 2 执行引导，反馈引导结果
        print('2 执行引导，反馈引导结果')
        yd_res = [2, 6, 60, 2]
        hn_plc.set_yd_res_placePhone(yd_res)

        # 3 等待获取检测触发
        print('3 等待获取检测触发')
        while 1:
            is_jc = hn_plc.get_is_jc_placePhone()  #
            if is_jc == 1:
                print(f'is_jc {is_jc}')
                hn_plc.set_zero_is_jc_placePhone()
                break

        # 4 反馈检测结果
        print('4 反馈检测结果')
        jc_res = 1
        hn_plc.set_jc_res_placePhone(jc_res)

    hn_plc.close()


def test_HuoniPlcClientBase():
    hn_plc = HuoniPlcClientBase(config.PlacePhone)
    # hn_plc = HuoniPlcClientBase(config.PlaceInstruction)
    hn_plc.connect()
    for i in range(200):

        hn_plc.set_scan_res(f'123456789{i}')
        # value = hn_plc.get_scan_res()
        # print(value)
        time.sleep(0.2)
    hn_plc.close()


if __name__ == "__main__":
    # test_HuoniPlcClinet()
    test_HuoniPlcClientBase()
